// 节流
const test = () => {
  console.log('---------------');
};
function throttle(f, delay = 3000) {
  let timer = null;
  return (...args) => {
    if (timer) return;

    f(...args);

    timer = setTimeout(() => {
      timer = null;
    }, delay);
  };
}
const d = throttle(test);
// 防抖
function debounce(f, delay) {
  let timer = null;
  return (...args) => {
    if (timer) {
      clearTimeout(timer);
    }
    timer = setTimeout(() => {
      f(...args);
      timer = null;
    }, delay);
  };
}

Promise._all = (list) => {
  const results = [];
  let count = 0;
  return new Promise((resolve, reject) => {
    list.forEach((p, index) => {
      Promise.resolve(p)
        .then((res) => {
          results[index](res);
          count++;
          if (count === results.length) resolve(results);
        })
        .catch(reject);
    });
  });
};

function quickSort(arr) {
  if (arr.length < 2) return arr;

  let cur = arr[arr.length - 1];
  const left = arr.filter((v, i) => v <= cur && i !== arr.length - 1);
  const right = arr.filter((v) => v > cur);
  return [...quickSort(left), cur, ...quickSort(right)];
}

function add(a, b) {
  const maxLen = Math.max(a.length, b.length)

  a = a.padStart(maxLen, 0)
  b = b.padStart(maxLen, 0)

  let t = 0
  let f = 0 // 进位
  let sum = ""

  for(let i = maxLen - 1; i >= 0; i--) {
    t = parseInt(a[i]) + parseInt(b[i]) + f

    f = Math.floor(t / 10)

    sum = (t % 10) + sum
  }

  if (f) return f + sum
  return sum
}

const ajax = (method, url, success, fail) => {
  const request = new XMLHttpRequest()
  request.open(method, url)
  request.onreadystatechange = () => {
    if (request.readyState === 4) {
      if (request.status >= 200 && request.status < 300 || request.status === 304) {
        success(request)
      } else {
        fail(request)
      }
    }
  }
  request.send()
}

Promise._all = (promises) => {
  const results = []
  let count = 0

  return new Promise((resolve, reject) => {
    promises.forEach((promise, index) => {
      Promise.resolve(promise).then(res => {
        results[index] = res
        count++
        if (count === promises.length) {
          resolve(results)
        }
      }).catch(reject)
    })
  })
}

const deepClone = (o, cache = new WeakMap()) => {
  if (cache.has(o)) return cache.get(o)
  if (typeof o !== 'object') return o
  if (o === null) return null
  if (o instanceof RegExp) return new RegExp(o)
  if (o instanceof Date) return new Date(o)

  const cloneObj = o.constructor()
  cache.set(o, cloneObj)
  for(let key in o) {
    if (o.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(o[key], cache)
    }
  }
}

const quickSort = (arr) => {
  if (arr.length < 2) return arr

  const cur = arr[arr.length - 1]

  const left = arr.filter((item, i) => item <= cur && i !== arr.length - 1)
  const right = arr.filter((item, i) => item > cur)

  return [...quickSort(left), cur, ...quickSort(right)]
}

const add = (a, b) => {
  const maxLen = Math.max(a.length, b.length)

  a = a.padStart(maxLen, '0')
  b = b.padStart(maxLen, '0')

  let f = 0 // 进位
  let res = ''
  for(let i = maxLen - 1; i >= 0; i--) {
    const temp = parseInt(a[i]) + parseInt(b[i]) + f
    f = Math.floor(temp / 10)
    res = `${temp % 10}${res}`
  }
  res = f > 0 ? `${f}${res}` : res
}

Function.prototype.myCall = function (obj, ...args) {
  if (obj === undefined || obj === null) {
    obj = globalThis
  }
  obj.fn = this
  const res = obj.fn(...args)
  delete obj.fn
  return res
}

Function.prototype.myApply = function (obj, args) {
  if (obj === undefined || obj === null) {
    obj = globalThis
  }
  obj.fn = this
  const res = obj.fn(...args)
  delete obj.fn
  return res
}

Function.prototype.myBind = function (obj, ...args) {
  const that = this
  const fn = function() {
    if (this instanceof fn) { // 处理new bind后的函数
      return new that(...args)
    } else {
      that.call(obj, ...args)
    }
  }
  return fn
}

function curry(fn) {
  let params = []
  const next = function(...args) {
    params = [...params, ...args]
    if (params.length < fn.length) {
      return next
    } else {
      return fn.apply(this, params)
    }
  }

  return next
}

function sum(a, b, c) {
  return a + b + c;
}

let sumFn = curry(sum);
console.log(sumFn(1)(2)(3));

const myNew = (fn, ...args) => {
  // let obj = {}
  // obj.__proto__ = fn.prototype
  let obj = Object.create(fn.prototype)
  const res = fn.apply(obj, args)
  return res instanceof Object ? res : obj
}

const myInstanceof = (obj, Fn) => {
  let proto = obj.__proto__
  while(proto) {
    if (proto === Fn.prototype) {
      return true
    }
    proto = proto.__proto__
  }
  return false
}

const flat1 = (arr) => {
  if (Array.isArray(arr)) return
  return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? flat1(cur) : cur), [])
}

const flat2 = (arr) => {
  if (Array.isArray(arr)) return

  const stack = [arr]
  const res = []
  while(stack.length) {
    const cur = stack.shift()
    if (Array.isArray(cur)) {
      stack.push(...cur)
    } else {
      res.push(cur)
    }
  }
  return res
}